﻿/* guoqiang.zhang2009.5.12
 * 
 */

using System;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.ComponentModel;
using System.Web.UI;
using System.Drawing.Design;
using System.Security.Permissions;

[assembly: WebResource("Bpms.Control.js.jquery.js", "text/javascript")]
[assembly: WebResource("Bpms.Control.js.jquery.dd.js", "text/javascript")]
[assembly: WebResource("Bpms.Control.css.jquery.dd.css", "text/css")]
[assembly: WebResource("Bpms.Control.image.jquery.dd.bg.gif", "image/gif")]

namespace Bpms.Control
{
    /// <summary>
    /// 能支持optgroup的dropdownlist
    /// </summary>
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [DefaultProperty("ExtendedItems")]
    public class ExtendedDropDownList : DropDownList
    {
        #region Private members
        private ExtendedListItemCollection _extendedItems;
        internal const string _optGroupAttributeKey = "optgroup";
        internal const string _separator = "#";
        bool _optGroupStarted = false;
        bool _selected = false;
        #endregion

        #region Public properties
        /// <summary>
        /// 获取optgroup 列表项
        /// </summary>
        /// <value>具有optgroup属性的列表项</value>
        [Category("Default"), Description("The items in a grouped manner."), DefaultValue((string)null), MergableProperty(false), NotifyParentProperty(true)]
        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public ExtendedListItemCollection ExtendedItems
        {
            get
            {
                if (null == this._extendedItems)
                {
                    this._extendedItems = new ExtendedListItemCollection(base.Items);
                }

                return this._extendedItems;
            }
        }

        /// <summary>
        /// 获取正常的列表项
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Web.UI.WebControls.ListItemCollection"/>普通列表项</returns>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new ListItemCollection Items
        {
            get
            {
                if (null == this._extendedItems)
                {
                    this._extendedItems = new ExtendedListItemCollection(base.Items);
                }

                return this._extendedItems._wrappedCollection;
            }

        }

        /// <summary>
        /// 获取选取项
        /// </summary>
        /// <value>扩展的列表项</value>
        public ExtendedListItem SelectedItemExtended
        {
            get { return new ExtendedListItem(this.SelectedItem); }
        }

        /// <summary>
        /// 获取选取的列表项的分组名
        /// </summary>
        public string SelectedGroup
        {
            get
            {
                ExtendedListItem item = this.SelectedItemExtended;

                if (item.GroupingType == ListItemGroupingType.New)
                {
                    return item.GroupingText;
                }
                else if (item.GroupingType == ListItemGroupingType.None)
                {
                    return string.Empty;
                }
                else
                {
                    //往上一级查找
                    int tmpIdx = this.ExtendedItems.IndexOf(item) - 1;

                    while (tmpIdx >= 0)
                    {
                        if (this.ExtendedItems[tmpIdx].GroupingType == ListItemGroupingType.New)
                        {
                            return this.ExtendedItems[tmpIdx].GroupingText;
                        }

                        tmpIdx--;
                    }

                    //找不到选择的组
                    return string.Empty;
                }
            }
        }

        #endregion

        #region Methods
        /// 复写saveviewstat()函数
        /// </summary>
        protected override object SaveViewState()
        {
            // 用一个object数组来承载两类数据，一为base的视图状态，在0位置
            // 一为其他的本控件需要的列表项
            object[] state = new object[this.Items.Count + 1];

            object baseState = base.SaveViewState();
            state[0] = baseState;

            // 列表项是否包含属性标记，用来判断是否返回base的普通listitem还是
            // 本控件的扩展listitem
            bool itemHasAttributes = false;
            for (int i = 0; i < this.Items.Count; i++)
            {
                if (this.Items[i].Attributes.Count > 0)
                {
                    itemHasAttributes = true;

                    // 用obj数组来承载属性标记的key/value对
                    object[] attribKV = new object[this.Items[i].Attributes.Count * 2];
                    int k = 0;

                    foreach (string key in this.Items[i].Attributes.Keys)
                    {
                        attribKV[k++] = key;
                        attribKV[k++] = this.Items[i].Attributes[key];
                    }

                    state[i + 1] = attribKV;
                }
            }

            if (itemHasAttributes)
            {
                return state;
            }
            else
            {
                return baseState;
            }
        }

        /// <summary>
        /// 装载视图状态
        /// </summary>
        /// <param name="savedState">视图状态</param>
        protected override void LoadViewState(object savedState)
        {
            if (savedState == null)
            {
                return;
            }

            // 查看视图状态是obj还是obj数组
            if (savedState is object[])
            {
                // 数组
                object[] state = (object[])savedState;
                base.LoadViewState(state[0]);   // base加载视图，数据为save时的第零个位置的值

                for (int i = 1; i < state.Length; i++)
                {
                    if (state[i] != null)
                    {
                        // 保存属性
                        object[] attribKV = (object[])state[i];
                        for (int k = 0; k < attribKV.Length; k += 2)
                        {
                            this.Items[i - 1].Attributes.Add(attribKV[k].ToString(),
                                                           attribKV[k + 1].ToString());
                        }
                    }
                }
            }
            else
            {
                // 扩展项数量为零
                base.LoadViewState(savedState);
            }
        }

        /// <summary>
        /// Render
        /// </summary>
        /// <param name="writer"><see cref="T:System.Web.UI.HtmlTextWriter"/>当前page的htmltextwriter</param>
        protected override void RenderContents(HtmlTextWriter writer)
        {
            if (this.Items.Count > 0)
            {
                for (int i = 0; i < this.ExtendedItems.Count; i++)
                {
                    ExtendedListItem item = this.ExtendedItems[i];

                    // 当前的项是optgroup的第一项 ，相当于==>.Attributes[_optGroupAttributeKey] != null)
                    if (item.GroupingType == ListItemGroupingType.New)
                    {
                        // 先写个optgroup项，再写普通项
                        WriteOptionGroup(item, writer);

                        WriteOption(item, writer);
                    }
                    else if (item.GroupingType == ListItemGroupingType.Inherit)// 当前项的前面还有其他optgroup里的项
                    {
                        WriteOption(item, writer);
                    }
                    else // 普通项
                    {
                        // 封口</optgroup>
                        if (_optGroupStarted)
                        {
                            writer.WriteEndTag("optgroup");
                        }

                        _optGroupStarted = false;

                        WriteOption(item, writer);
                    }
                }

                // 封口</optgroup>
                if (_optGroupStarted)
                {
                    writer.WriteEndTag("optgroup");
                }
            }
        }

        /// <summary>
        /// 最后一次HTML改动之前注册js,css
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            AddCss("Control.css.jquery.dd.css");
            AddJs("Control.js.jquery.js", "Control.js.jquery.dd.js");
            if (this.Page != null)
            {
                this.Page.ClientScript.RegisterStartupScript(this.GetType(), "", string.Format("<script>MSDropDown.init('#{0}');</script>", this.ClientID));
            }
        }

        /// <summary>
        /// 向页面添加css引用
        /// </summary>
        /// <param name="cssNames"></param>
        private void AddCss(params string[] cssNames)
        {
            if (cssNames is string[])
            {
                if (this.Page == null || this.Page.Header == null)
                {
                    return;
                }

                foreach (string cssName in cssNames)
                {
                    if (!this.Page.ClientScript.IsStartupScriptRegistered(string.Format("_bpms_{0}_", cssName)))
                    {
                        HtmlLink css = new HtmlLink();

                        css.Attributes.Add("type", "text/css");
                        css.Attributes.Add("rel", "stylesheet");
                        css.Attributes.Add("src", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), cssName));

                        if (this.Page.Header != null)
                        {
                            this.Page.Header.Controls.Add(css);
                            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), string.Format("_bpms_{0}_", cssName), "");
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 向页面添加js引用
        /// </summary>
        /// <param name="jsNames"></param>
        private void AddJs(params string[] jsNames)
        {
            if (jsNames is string[])
            {
                if (this.Page == null || this.Page.Header == null)
                {
                    return;
                }

                foreach (string jsName in jsNames)
                {
                    if (!this.Page.ClientScript.IsStartupScriptRegistered(string.Format("_bpms_{0}_", jsName)))
                    {
                        HtmlGenericControl script = new HtmlGenericControl("script");

                        script.Attributes.Add("type", "text/css");
                        script.Attributes.Add("rel", "stylesheet");
                        script.Attributes.Add("src", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), jsName));

                        if (this.Page.Header != null)
                        {
                            this.Page.Header.Controls.Add(script);
                            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), string.Format("_bpms_{0}_", jsName), "");
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 写optgroup项
        /// </summary>
        /// <param name="item">扩展的item</param>
        /// <param name="writer">writer</param>
        private void WriteOptionGroup(ExtendedListItem item, HtmlTextWriter writer)
        {
            //封口</optgroup>
            if (_optGroupStarted)
            {
                writer.WriteEndTag("optgroup");
            }

            //<optgroup>
            writer.WriteBeginTag("optgroup");
            writer.WriteAttribute("label", item.GroupingText);
            //disabled属性
            if (!item.Enabled)
            {
                writer.WriteAttribute("disabled", "disabled");
            }
            // Css属性
            if (!string.IsNullOrEmpty(item.GroupCssClass))
            {
                writer.WriteAttribute("class", item.GroupCssClass);
            }
            writer.Write('>');
            // 开始写<optgroup>
            _optGroupStarted = true;
        }

        /// <summary>
        /// 写普通的option项
        /// </summary>
        /// <param name="item">普通item</param>
        /// <param name="writer">writer</param>
        private void WriteOption(ExtendedListItem item, HtmlTextWriter writer)
        {
            writer.WriteBeginTag("option");
            if (item.Selected)
            {
                if (_selected)
                {
                    this.VerifyMultiSelect(); //引发异常，dropdownlist不允许多选
                }
                _selected = true;
                writer.WriteAttribute("selected", "selected");
            }

            if (!string.IsNullOrEmpty(item.CssClass))
            {
                writer.WriteAttribute("class", item.CssClass);
            }

            writer.WriteAttribute("value", item.Value, true);

            if (item.Attributes.Count > 0)
            {
                StateBag bag = new StateBag();
                foreach (string attrKey in item.Attributes.Keys)
                {
                    if (attrKey.IndexOf(ExtendedListItem._attrPrefix) == -1)
                    {
                        bag.Add(attrKey, item.Attributes[attrKey]);
                    }
                }

                System.Web.UI.AttributeCollection coll = new System.Web.UI.AttributeCollection(bag);

                coll.Render(writer);
            }

            if (this.Page != null)
            {
                // 注册验证，如果页面开启验证，同样不允许以js方式更改dd的items
                this.Page.ClientScript.RegisterForEventValidation(this.UniqueID, item.Value);
            }

            writer.Write('>');
            HttpUtility.HtmlEncode(item.Text, writer);
            writer.WriteEndTag("option");
            writer.WriteLine();
        }
        #endregion
    }


}
